package com.wenlin.myproduction.widget;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.wenlin.myproduction.R;
import com.wenlin.myproduction.bean.NewPlanEn;
import com.wenlin.myproduction.util.Checker;
import com.wenlin.myproduction.util.LogUtils;
import com.wenlin.myproduction.util.ScreenUtils;
import com.wenlin.myproduction.util.UI;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * 学习计划的轮播控件，不需要自动轮播
 *
 * @author 文琳
 * @time 2020/11/10 14:00
 * @desc 学习计划的轮播控件，不需要自动轮播
 */
public class BookBannerView extends View {
    private static final float MIN_RATIO = 0.23333f;//小个的条目与正常大小的条目的比例
    //打卡状态
    private static final int PUNCH_NOT_YET = 0;//尚未打卡
    private static final int PUNCH_WAIT_TO_SHARE = 1;//等待分享
    private static final int PUNCH_COMPLETED = 2;//打卡完成
    //其他
    private static final int TEXT_MAX_LENGTH = 20;//学习计划标题太长时截取前n个字符，然后加上“...”
    private static final int ANIM_DUR = 500;
    //有无数据的状态码
    private static final int STATE_HAS_DATA = 0;
    private static final int STATE_NO_DATA = 1;
    //尺寸、比例
    private int viewWidth;//1200
    private int viewHeight;
    private float paddingBottom;//留出画indicator的空间
    private float bigWidth;
    private float smallWidth;
    private float textSize28, textSize30, textSize36, textSize40, textSize44;
    private float picWidth, picHeight;
    private float teacherWidth, teacherHeight;
    private float bgWhiteWidth, bgWhiteHeight;
    private float maskWidth, maskHeight;
    private float maxTitleOrTeacherNameWidth;
    private float maxTitleOrTeacherNameWidth2;//当没有打卡进度也没有锁定图片的时候，可以显示更多的文字
    private float bookRightRadius;
    private float bookLeftRadius;
    private float progressCircleRadius;
    private float progressLineWidth;
    private float lockPaddingStart;
    private float lockPaddingBottom;
    private float lockWidth, lockHeight;
    private float minScrollDistance;//大致上弄个值
    private float maxClickScrollDistance;//大致上弄个值
    private float dotHeight;
    private float dotDistance;
    private float indicatorHeight;
    private float indicatorWidth;
    //颜色
    private int colorText = Color.parseColor("#ff333333"), colorPunchText = Color.parseColor("#ff00dbad"), colorIndicator = Color.parseColor("#ffd1d1d1");
    private int colorProgressBg = Color.parseColor("#ffececec"), colorProgressFt = Color.parseColor("#ff00dbad");
    private int colorDotDark = Color.parseColor("#ff00dbad"), colorDotLight = Color.parseColor("#ffe5fbf7");
    //位图
    private Bitmap bitmapCoverDefault;
    private Bitmap bitmapTeacherDefault;
    private Bitmap bitmapBgWhite;
    private Bitmap bitmapMask;
    private Bitmap bitmapLock;
    //画图工具
    private Path path;
    private Paint paint, paintProgress;
    private Rect rect;
    private RectF rectF;
    private TextPaint textPaint;
    private PorterDuffXfermode porterDuffXfermode;
    private CountDownTimer timer;//加载中的指示点闪动用到的倒计时
    private ValueAnimator valueAnimator;//值动画
    private callback callback;//回调
    private int dotCount;//加载中的指示点的计数
    private int progress;//打卡进度条的进度
    private int statePunch;//打卡状态
    private List<BannerBean> list;//数据集合
    private float scrollXOffset;//滑动偏移值
    private int currentIndex = 0;//当前最大的条目的脚标
    private int latestUnlockIndex;//最新的解锁条目的位置
    private float lastX;//上一个手指按下的x坐标
    private float valueFloat;//动画用到的值
    private int state;

    public BookBannerView(Context context) {
        this(context, null);
    }

    public BookBannerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    /**
     * 初始化
     */
    private void initialize() {
        //画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        //画进度条的画笔
        paintProgress = new Paint();
        paintProgress.setAntiAlias(true);
        paintProgress.setDither(true);
        paintProgress.setStyle(Paint.Style.STROKE);
        paintProgress.setStrokeWidth(progressLineWidth);
        paintProgress.setStrokeCap(Paint.Cap.ROUND);
        //文字画笔
        textPaint = new TextPaint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        //计算文字宽高的方框
        rect = new Rect();
        rectF = new RectF();
        //路径
        path = new Path();
        //裁剪模式
        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);//模式：显示前景图并取交集（IN）。（SRC source表示源图片，背景图是DST destination目的地）
        initSize();
    }

    private void initSize() {
        viewWidth = ScreenUtils.getCurrentScreenWidth(getContext());
        LogUtils.e(viewWidth);
        int unitSize = viewWidth / 1200;
        viewHeight = unitSize * 1220;
        paddingBottom = unitSize * 60;
        bigWidth = unitSize * 938;
        smallWidth = viewWidth - bigWidth;//1200-938=262
        textSize28 = unitSize * 28;
        textSize30 = unitSize * 30;
        textSize36 = unitSize * 36;
        textSize40 = unitSize * 40;
        textSize44 = unitSize * 44;
        picWidth = unitSize * 711;
        picHeight = unitSize * 860;
        teacherWidth = unitSize * 140;
        teacherHeight = unitSize * 140;
        bgWhiteWidth = unitSize * 920;
        bgWhiteHeight = unitSize * 900;
        maskWidth = unitSize * 811;
        maskHeight = unitSize * 920;
        maxTitleOrTeacherNameWidth = unitSize * 450;
        maxTitleOrTeacherNameWidth2 = unitSize * 600;
        bookRightRadius = unitSize * 77;
        bookLeftRadius = unitSize * 21;
        progressCircleRadius = unitSize * 63;
        progressLineWidth = unitSize * 6;
        lockPaddingStart = unitSize * 759;
        lockPaddingBottom = unitSize * 155;
        lockWidth = unitSize * 50;
        lockHeight = unitSize * 70;
        minScrollDistance = unitSize * 20;
        maxClickScrollDistance = unitSize * 10;
        dotHeight = unitSize * 30;
        dotDistance = unitSize * 26;
        indicatorHeight = unitSize * 20;
        indicatorWidth = 3 * indicatorHeight;
        initBitmap();
    }

    private void initBitmap() {
        //位图的初始化
        bitmapCoverDefault = BitmapFactory.decodeResource(getResources(), R.mipmap.home_bg_loading);
        bitmapCoverDefault = handleBitmap(bitmapCoverDefault, picWidth, picHeight);
        bitmapBgWhite = BitmapFactory.decodeResource(getResources(), R.mipmap.home_bg_white);
        bitmapBgWhite = handleBitmap(bitmapBgWhite, bgWhiteWidth, bgWhiteHeight);
        bitmapMask = BitmapFactory.decodeResource(getResources(), R.mipmap.home_mask_book);
        bitmapMask = handleBitmap(bitmapMask, maskWidth, maskHeight);
        bitmapLock = BitmapFactory.decodeResource(getResources(), R.mipmap.home_ic_lock);
        bitmapLock = handleBitmap(bitmapLock, lockWidth, lockHeight);
        //占位数据
        setDefaultNullData();
        startTimerForLoading();
    }

    /**
     * 设置默认的两个占位数据
     */
    public void setDefaultNullData() {
        list = new ArrayList<>();
        list.add(new BannerBean("", "", "", "", 0, false, true, null));
        list.add(new BannerBean("", "", "", "", 1, false, false, null));
        list.get(0).setX(0);
        list.get(0).setOldX(0);
        list.get(0).setRatio(1);
        list.get(0).setOldRatio(1);
        list.get(0).setWidth(bigWidth);
        list.get(0).setOldWidth(bigWidth);
        list.get(1).setX(bigWidth);
        list.get(1).setOldX(bigWidth);
        list.get(1).setRatio(MIN_RATIO);
        list.get(1).setOldRatio(MIN_RATIO);
        list.get(1).setWidth(smallWidth);
        list.get(1).setOldWidth(smallWidth);
        invalidate();
    }

    /**
     * 设置初始数据
     *
     * @param newList 数据集合
     */
    public void resetData(List<BannerBean> newList) {
        resetData(newList, 0);
    }

    /**
     * 设置数据
     *
     * @param newList      数据集合
     * @param currentIndex 设置当前显示的数据
     */
    public void resetData(List<BannerBean> newList, int currentIndex) {
//        UI.releaseValueAnimator(valueAnimator);//是否需要添加这句？如果不加的话，当下拉刷新时滑动控件，额，好像也行。如果加上的话会立刻停止滑动动画，并且恢复到正确位置，看起来是闪现过去。
        //释放bitmap
        if (Checker.hasList(list)) {
            for (int i = 0; i < list.size(); i++) {
                BannerBean bean = list.get(i);
                Bitmap bitmapCover = bean.getBitmapCover();
                if (bitmapCover != null && !bitmapCover.isRecycled()) {
                    bitmapCover.recycle();
                    bitmapCover = null;
                    list.get(i).setBitmapCover(null);
                }
                Bitmap bitmapTeacher = bean.getBitmapTeacher();
                if (bitmapTeacher != null && !bitmapTeacher.isRecycled()) {
                    bitmapTeacher.recycle();
                    bitmapTeacher = null;
                    list.get(i).setBitmapTeacher(null);
                }
            }
            list.clear();
        }
        setData(newList, currentIndex);
        //开始加载图片并开启加载中的动画
        if (Checker.hasList(newList)) {
            state = STATE_HAS_DATA;
            startTimerForLoading();
            handleBitmapCoverAndTeacherHead();
        } else {
            state = STATE_NO_DATA;
            UI.releaseTimer(timer);
        }
    }

    /**
     * 静默更新学习计划数据，而不改变BannerView的状态
     *
     * @param newList 新数据
     */
    public void updatePlanEnDataQuietly(List<NewPlanEn> newList) {
        if (Checker.hasNoList(newList) || Checker.hasNoList(list)) return;
        if (newList.size() != list.size()) return;
        for (int i = 0; i < list.size(); i++) {
            //在HomeFragment已经针对id等进行了判断，这里直接对应位置替换即可
            list.get(i).setPlanEn(newList.get(i));
        }
//        LogManage.getInstance().addPadLog("BannerView学习计划静默更新成功");
        invalidate();
    }

    /**
     * 设置数据并滑动到指定位置
     *
     * @param newList      新的数据集合
     * @param currentIndex 当前位置
     */
    private void setData(List<BannerBean> newList, int currentIndex) {
        list = newList;
        this.currentIndex = Checker.hasList(list) ? currentIndex % list.size() : 0;//避免脚标越界
        latestUnlockIndex = this.currentIndex;
        if (Checker.hasList(list)) {
            for (int i = 0; i < list.size(); i++) {
                float x;
                float ratio;
                float width;
                if (i <= currentIndex) {//当currentIndex=0时，脚标为0的x为0；当currentIndex=1时，脚标为0的x为-bigWidth，脚标为1的x为0；
                    x = bigWidth * (i - currentIndex);
                    ratio = 1;
                    width = bigWidth;
                } else {
                    //当currentIndex=0时，脚标为0的x走上边的判断为0，然后后面的都走下边的判断：脚标为1的x为bigWidth，脚标为2的x为bigWidth+smallWidth。
                    //当currentIndex=1时，脚标为0的x走上边的判断为-bigWidth，脚标为1的x走上边的判断为0；然后后面的都走下边的判断：脚标为2的x为bigWidth，脚标为3的x为bigWidth+smallWidth。
                    x = bigWidth + smallWidth * (i - 1 - currentIndex);
                    ratio = MIN_RATIO;
                    width = smallWidth;
                }
                list.get(i).setX(x);
                list.get(i).setRatio(ratio);
                list.get(i).setWidth(width);
                list.get(i).setOldX(x);
                list.get(i).setOldRatio(ratio);
                list.get(i).setOldWidth(width);
            }
        } else {
            setDefaultNullData();
        }
        scrollXOffset = 0;
//        LogManage.getInstance().addPadLog("BannerView学习计划更新成功");
        invalidate();
    }

    /**
     * 获取原计划集合
     *
     * @return 所求
     */
    public List<NewPlanEn> getOriPlanData() {
        List<NewPlanEn> newList = new ArrayList<>();
        if (Checker.hasList(list)) {
            for (BannerBean bean :
                    list) {
                if (Checker.notNull(bean) && Checker.notNull(bean.getPlanEn()))
                    newList.add(bean.getPlanEn());
            }
        }
        return newList;
    }

    /**
     * 开始加载中的指示点用到的倒计时
     */
    private void startTimerForLoading() {
        UI.releaseTimer(timer);
        timer = new CountDownTimer(Integer.MAX_VALUE, 500) {
            @Override
            public void onTick(long millisUntilFinished) {
                dotCount = ++dotCount % 3;
                postInvalidate();
            }

            @Override
            public void onFinish() {
                //nothing
            }
        }.start();
    }

    /**
     * 设置当前显示的条目
     *
     * @param currentIndex 脚标
     */
    public void setCurrentUnlockItem(int currentIndex) {
        setData(list, currentIndex);
    }

    /**
     * 设置回调
     *
     * @param callback 回调
     */
    public void setCallback(callback callback) {
        this.callback = callback;
    }

    /**
     * 设置打卡状态
     *
     * @param statePunch 打卡状态，只能是 PUNCH_NOT_YET；PUNCH_WAIT_TO_SHARE；PUNCH_COMPLETED 的其中一个
     */
    private void setPunchState(int statePunch) {
        this.statePunch = statePunch;
    }

    /**
     * 设置今日未打卡
     */
    public void setPunchNotYet() {
        setPunchState(PUNCH_NOT_YET);
        setProgress(0);
//        invalidate();
    }

    /**
     * 设置打卡待分享
     */
    public void setPunchWaitToShare() {
        setPunchState(PUNCH_WAIT_TO_SHARE);
        setProgress(100);
//        invalidate();
    }

    /**
     * 设置打卡完成
     */
    public void setPunchCompleted() {
        setPunchState(PUNCH_COMPLETED);
        setProgress(100);
//        invalidate();
    }

    /**
     * 设置进度
     *
     * @param progress 进度
     */
    public void setProgress(int progress) {
        this.progress = progress;
        invalidate();
    }

    /**
     * 格式化缩放比例
     *
     * @param ratio 缩放比例
     * @return 所求
     */
    private float formatRatio(float ratio) {
        if (ratio > 1) ratio = 1;
        if (ratio < MIN_RATIO) ratio = MIN_RATIO;
        return ratio;
    }

    /**
     * 处理封面和老师头像图片
     */
    private void handleBitmapCoverAndTeacherHead() {
        if (Checker.isNull(list)) return;
        //下方代码处理图片，并且
        if (Checker.isNull(bitmapCoverDefault) || bitmapCoverDefault.isRecycled())
            bitmapCoverDefault = BitmapFactory.decodeResource(getResources(), R.mipmap.home_bg_loading);
        if (Checker.isNull(bitmapTeacherDefault) || bitmapTeacherDefault.isRecycled())
            bitmapTeacherDefault = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_teacher_default_0);
        Observable.from(list)
                .map(bannerBean -> {
                    Bitmap bitmap = null;
                    try {
                        if (Checker.notNull(getContext()))
                            bitmap = Glide.with(getContext()).asBitmap().load(bannerBean.getCover()).submit().get();
                    } catch (ExecutionException | InterruptedException e) {
                        e.printStackTrace();
                    }
                    bannerBean.setBitmapCover(bitmap);
                    return bannerBean;
                })
                .map(bannerBean -> {
                    Bitmap bitmap = null;
                    try {
                        if (Checker.notNull(getContext()))
                            bitmap = Glide.with(getContext()).asBitmap().load(bannerBean.getTeacherHead()).submit().get();
                    } catch (ExecutionException | InterruptedException e) {
                        e.printStackTrace();
                    }
                    bannerBean.setBitmapTeacher(bitmap);
                    return bannerBean;
                })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<BannerBean>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
//                    LogUtils.e("学习中心书目图片异常");
                    }

                    @Override
                    public void onNext(BannerBean bannerBean) {
                        Bitmap bitmapCover = bannerBean.getBitmapCover();
                        if (bitmapCover == null) bitmapCover = bitmapCoverDefault;//学习中心书目图片异常
                        Bitmap bitmapTeacher = bannerBean.getBitmapTeacher();
                        if (bitmapTeacher == null) bitmapTeacher = bitmapTeacherDefault;
                        //处理图片，进行缩放
                        if (Checker.hasList(list)) {
                            for (int j = 0; j < list.size(); j++) {
                                BannerBean temp = list.get(j);
                                if (temp.getPosition() == bannerBean.getPosition()) {
                                    list.get(j).setBitmapCover(handleBitmap(bitmapCover, picWidth, picHeight));
                                    list.get(j).setBitmapTeacher(handleBitmap(bitmapTeacher, teacherWidth, teacherHeight));
                                    break;
                                }
                            }
                        }
                        postInvalidate();
                        tryAbortDotTimerAfterAllCoverBitmapHandled();
                    }
                });
    }

    /**
     * 当所有的图片都已经处理完成则关闭控制封面加载中的指示点的倒计时
     */
    private void tryAbortDotTimerAfterAllCoverBitmapHandled() {
        boolean isAllHandled = true;
        if (Checker.hasList(list)) {
            for (int i = 0; i < list.size(); i++) {
                if (Checker.isNull(list.get(i).getBitmapCover())) {
                    isAllHandled = false;
                    break;
                }
            }
        }
        if (isAllHandled) UI.releaseTimer(timer);
    }

    /**
     * 设置滑动偏移
     */
    private void setAllXOffset() {
        if (Checker.hasNoList(list)) return;
        float ratio;
        float x;
        float width;
        for (int i = 0; i < list.size(); i++) {
            BannerBean bean = list.get(i);
            if (scrollXOffset > 0) {//右滑，看x为-bigWidth,0,bigWidth这三个item
                if (bean.getOldX() == -bigWidth) {//从-bigWidth到0
                    list.get(i).setX(bean.getOldX() + scrollXOffset);
                    list.get(i).setRatio(1);
                    list.get(i).setWidth(bigWidth);
                } else if (bean.getOldX() == 0) {//从0到bigWidth
                    x = bean.getOldX() + scrollXOffset;
                    list.get(i).setX(x);
                    ratio = formatRatio(MIN_RATIO + Math.abs(bigWidth - x) / bigWidth * (1 - MIN_RATIO));
                    list.get(i).setRatio(ratio);
                    width = ratio * bigWidth;
                    if (width < smallWidth) width = smallWidth;//让变化中的条目最小宽度为smallWidth
                    list.get(i).setWidth(width);
                } else if (bean.getOldX() == bigWidth) {//从bigWidth到viewWidth
                    list.get(i).setX(bean.getOldX() + scrollXOffset * smallWidth / bigWidth);
                    list.get(i).setRatio(MIN_RATIO);
                    list.get(i).setWidth(smallWidth);
                }
            } else {//左滑，看x为0，bigWidth，viewWidth这三个item
                if (bean.getOldX() == 0) {
                    list.get(i).setX(bean.getOldX() + scrollXOffset);
                    list.get(i).setRatio(1);
                    list.get(i).setWidth(bigWidth);
                } else if (bean.getOldX() == bigWidth) {
                    x = bean.getOldX() + scrollXOffset;
                    list.get(i).setX(x);
                    ratio = formatRatio(MIN_RATIO + Math.abs(bigWidth - x) / bigWidth * (1 - MIN_RATIO));
                    list.get(i).setRatio(ratio);
                    width = ratio * bigWidth;
                    if (width < smallWidth) width = smallWidth;//让变化中的条目最小宽度为smallWidth
                    list.get(i).setWidth(width);
                } else if (bean.getOldX() == viewWidth) {
                    list.get(i).setX(bean.getOldX() + scrollXOffset * smallWidth / bigWidth);
                    list.get(i).setRatio(MIN_RATIO);
                    list.get(i).setWidth(smallWidth);
                }
            }
        }
    }

    /**
     * 自动跳到触摸点上的条目，如果是滑动，则滑到合适的条目
     *
     * @param x 触摸点的横坐标
     */
    private void autoSwitchItem(float x, float y) {
        boolean findItemAlready = false;
        if (Checker.hasNoList(list)) return;
        for (int i = 0; i < list.size(); i++) {
            BannerBean bean = list.get(i);
            if (Math.abs(scrollXOffset) < minScrollDistance) {//在一个10的范围内的滑动视为点击而不是滑动
                if (bean.getX() < x && (bean.getX() + bean.getWidth()) > x) {//如果找到了手指下的条目
                    float centerX = bean.getX() + bean.getWidth() / 2f;//找到中间线的横坐标
                    boolean clickSmallItemAndStartActivity = false;
                    if (centerX > 0 && centerX < bigWidth) {//让大条目的横坐标变成0
                        startAnimator(scrollXOffset, 0);
                        currentIndex = i;
                    } else if (bean.isUnlock() && centerX > bigWidth && centerX < viewWidth) {//如果小个条目是已解锁，则滑过来，如果未解锁，则走后面的点击事件，提示请先完成最新解锁的计划
                        startAnimator(scrollXOffset, -bigWidth);
                        currentIndex = i;
                        clickSmallItemAndStartActivity = true;
                    } else {//20201201 先前没有这个else{}的代码，加上这个可以修复滑动小距离时不会自动滑到目标条目的问题
                        startAnimator(scrollXOffset, 0);
                        currentIndex = i - 1;
                        if (currentIndex < 0) currentIndex = 0;
                    }
                    findItemAlready = true;
                    if (Math.abs(scrollXOffset) < maxClickScrollDistance) {
                        //点击事件
                        if (x > bigWidth && y < viewHeight - paddingBottom - 320)
                            return;//如果点击的是小条目上面的空间，就不做动作
                        if (Checker.notNull(callback)) {
                            if (Checker.isNull(bean.getPlanEn())) {//计划为空表示加载中
                                callback.onClickLoading(state == STATE_HAS_DATA ? "正在加载，请稍候~" : "当前等级没有学习计划");
                            } else if (!bean.isTodayCanRead() && i > 0 && Checker.notNull(list.get(i - 1).getPlanEn()) && list.get(i - 1).getPlanEn().CompleteFlag) {//点击第四个，如果第三个已经读完
                                callback.onClickTodayCanNotRead();
                            } else if (bean.isUnlock() || bean.getPosition() == 0) {//点击已解锁或者第一个
                                if (clickSmallItemAndStartActivity) {//如果点了小条目，并且此时小条目是可读的，则先滑动到左侧变成大条目，再去做跳转操作，避免跳转操作和滑动操作同时进行，造成控件卡顿
                                    postDelayed(() -> callback.onClickWithUnlock(bean.getPlanEn()), ANIM_DUR);
                                } else callback.onClickWithUnlock(bean.getPlanEn());
                            } else if (i - 1 >= 0) {//点击已锁定
                                callback.onClickWithLock(getFormatStr(list.get(latestUnlockIndex).getTitle()));
                            }
                        }
                    }
                    break;
                }
            } else if (scrollXOffset > minScrollDistance) {//向右滑动，找只显示部分的那个
                if (bean.getX() < 0 && bean.getX() + bean.getWidth() > 0) {
                    currentIndex = i;
                    startAnimator(scrollXOffset, bigWidth);
                    findItemAlready = true;
                    break;
                }
            } else if (scrollXOffset < -minScrollDistance) {//向左滑动，找靠左边的第一个
                if (bean.getX() > 0) {
                    currentIndex = i;
                    startAnimator(scrollXOffset, -bigWidth);
                    findItemAlready = true;
                    break;
                }
            }
        }
        //前面的情况都不符合，说明是第一个往右滑或者最后一个往左滑的情况，20210222 或者是在滑到最后一个计划后，直接点击了空白
        if (!findItemAlready) {
            //如果点击的是最后一个计划右边的空白
            if (Math.abs(scrollXOffset) < maxClickScrollDistance) {
                //点击事件
                if (x > bigWidth)
                    return;//如果点击的是空白，就不做动作
            }
            if (scrollXOffset >= 0) {
                currentIndex = 0;
            } else {
                currentIndex = list.size() - 1;
            }
            startAnimator(scrollXOffset, 0);
        }
    }

    /**
     * 开始动画
     *
     * @param start 动画的初始值
     * @param end   动画的结束值
     */
    private void startAnimator(float start, float end) {
        if (valueAnimator != null && valueAnimator.isRunning()) return;
        valueAnimator = ValueAnimator.ofFloat(start, end);
        valueAnimator.addUpdateListener(animation -> {
            valueFloat = (float) animation.getAnimatedValue();
            scrollXOffset = valueFloat;
            setAllXOffset();
            invalidate();
        });
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //同步新数据覆盖旧数据
                scrollXOffset = 0;
                if (Checker.hasList(list)) {//list 会空指针报错
                    for (int i = 0; i < list.size(); i++) {
                        if (i <= currentIndex) {
                            list.get(i).setRatio(1);
                            list.get(i).setWidth(bigWidth);
                            list.get(i).setX(-bigWidth * (currentIndex - i));
                            list.get(i).setOldRatio(1);
                            list.get(i).setOldWidth(bigWidth);
                            list.get(i).setOldX(-bigWidth * (currentIndex - i));
                        } else {
                            list.get(i).setRatio(MIN_RATIO);
                            list.get(i).setWidth(smallWidth);
                            list.get(i).setX(bigWidth + (i - currentIndex - 1) * smallWidth);
                            list.get(i).setOldRatio(MIN_RATIO);
                            list.get(i).setOldWidth(smallWidth);
                            list.get(i).setOldX(bigWidth + (i - currentIndex - 1) * smallWidth);
                        }
                    }
                }
                invalidate();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        double time = Math.ceil(Math.abs(end - start)) / bigWidth * ANIM_DUR;
        valueAnimator.setDuration((int) time);
        valueAnimator.start();
    }

    /**
     * 生成新的Bitmap图片
     *
     * @return 所求
     */
    private Bitmap handleBitmap(Bitmap bitmap, float newWidth, float newHeight) {
        Matrix matrix = new Matrix();//创建一个处理图片的类
        int width = bitmap.getWidth();//获取图片本身的大小(宽)
        int height = bitmap.getHeight();//获取图片本身的大小(高)
        float wS = newWidth / (width > 0 ? width : newWidth);//缩放比---->这块注意这个是新的宽度/高度除以旧的宽度
        float hS = newHeight / (height > 0 ? height : newHeight);//缩放比---->这块注意这个是新的宽度/高度除以旧的宽度
        matrix.postScale(wS, hS);//这块就是处理缩放的比例
        //matrix.setScale(sX,sY);//缩放图片的质量sX表示宽0.5就代表缩放一半,sX同样
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    }

    /**
     * 画条目
     *
     * @param canvas 画布
     * @param bean   对象
     */
    private void drawItem(Canvas canvas, BannerBean bean) {
        //画背景
        if (Checker.isNull(bitmapBgWhite) || bitmapBgWhite.isRecycled()) {
            bitmapBgWhite = BitmapFactory.decodeResource(getResources(), R.mipmap.home_bg_white);
            bitmapBgWhite = handleBitmap(bitmapBgWhite, bgWhiteWidth, bgWhiteHeight);
        }
        canvas.drawBitmap(bitmapBgWhite, bean.getX() + UI.getPx(R.dimen.wpx22), viewHeight - UI.getPx(R.dimen.wpx27) - UI.getPx(R.dimen.wpx900), paint);
        //画书
        //先画圆角矩形的path
        path.reset();
        //从左上角圆角的尾巴开始，按照顺时针进行绘制
        path.moveTo(bean.getX() + UI.getPx(R.dimen.wpx127), viewHeight - UI.getPx(R.dimen.wpx320) - picHeight);
        path.lineTo(bean.getX() + UI.getPx(R.dimen.wpx739), viewHeight - UI.getPx(R.dimen.wpx320) - picHeight);
        //右上角圆角
        rectF.set(bean.getX() + UI.getPx(R.dimen.wpx739) - bookRightRadius, viewHeight - UI.getPx(R.dimen.wpx320) - picHeight, bean.getX() + UI.getPx(R.dimen.wpx739) + bookRightRadius, viewHeight - UI.getPx(R.dimen.wpx320) - picHeight + bookRightRadius * 2);
        path.arcTo(rectF, -90, 90);
        //右边
        path.lineTo(bean.getX() + UI.getPx(R.dimen.wpx816), viewHeight - UI.getPx(R.dimen.wpx320) - bookRightRadius);
        //右下角圆角
        rectF.set(bean.getX() + UI.getPx(R.dimen.wpx739) - bookRightRadius, viewHeight - UI.getPx(R.dimen.wpx320) - bookRightRadius * 2, bean.getX() + UI.getPx(R.dimen.wpx739) + bookRightRadius, viewHeight - UI.getPx(R.dimen.wpx320));
        path.arcTo(rectF, 0, 90);
        //下边
        path.lineTo(bean.getX() + UI.getPx(R.dimen.wpx127), viewHeight - UI.getPx(R.dimen.wpx320));
        //左下角圆角
        rectF.set(bean.getX() + UI.getPx(R.dimen.wpx127) - bookLeftRadius, viewHeight - UI.getPx(R.dimen.wpx320) - bookLeftRadius * 2, bean.getX() + UI.getPx(R.dimen.wpx127) + bookLeftRadius, viewHeight - UI.getPx(R.dimen.wpx320));
        path.arcTo(rectF, 90, 90);
        //左边
        path.lineTo(bean.getX() + UI.getPx(R.dimen.wpx127) - bookLeftRadius, viewHeight - UI.getPx(R.dimen.wpx320) - picHeight + bookLeftRadius);
        //左上角圆角
        rectF.set(bean.getX() + UI.getPx(R.dimen.wpx127) - bookLeftRadius, viewHeight - UI.getPx(R.dimen.wpx320) - picHeight, bean.getX() + UI.getPx(R.dimen.wpx127) + bookLeftRadius, viewHeight - UI.getPx(R.dimen.wpx320) - picHeight + bookLeftRadius * 2);
        path.arcTo(rectF, 180, 90);
        path.close();
        paint.setColor(Color.WHITE);
        canvas.drawPath(path, paint);
        canvas.saveLayerAlpha(bean.getX() + UI.getPx(R.dimen.wpx105), viewHeight - UI.getPx(R.dimen.wpx320) - picHeight, bean.getX() + UI.getPx(R.dimen.wpx105) + picWidth, viewHeight - UI.getPx(R.dimen.wpx320), 255);
        canvas.drawPath(path, paint);
        paint.setXfermode(porterDuffXfermode);
        if (Checker.notNull(bean.getBitmapCover())) {//画封面
            canvas.drawBitmap(bean.getBitmapCover(), bean.getX() + UI.getPx(R.dimen.wpx106), viewHeight - UI.getPx(R.dimen.wpx320) - picHeight, paint);
        } else {//画加载中的占位图
            if (Checker.isNull(bitmapCoverDefault) || bitmapCoverDefault.isRecycled()) {
                bitmapCoverDefault = BitmapFactory.decodeResource(getResources(), R.mipmap.home_bg_loading);
                bitmapCoverDefault = handleBitmap(bitmapCoverDefault, picWidth, picHeight);
            }
            canvas.drawBitmap(bitmapCoverDefault, bean.getX() + UI.getPx(R.dimen.wpx106), viewHeight - UI.getPx(R.dimen.wpx320) - picHeight, paint);
        }
        paint.setXfermode(null);
        canvas.restore();
        if (Checker.isNull(bitmapMask) || bitmapMask.isRecycled()) {
            bitmapMask = BitmapFactory.decodeResource(getResources(), R.mipmap.home_mask_book);
            bitmapMask = handleBitmap(bitmapMask, maskWidth, maskHeight);
        }
        rectF.set(bean.getX() + UI.getPx(R.dimen.wpx75), viewHeight - UI.getPx(R.dimen.wpx280) - maskHeight, bean.getX() + UI.getPx(R.dimen.wpx75) + maskWidth, viewHeight - UI.getPx(R.dimen.wpx280));
        canvas.drawBitmap(bitmapMask, null, rectF, paint);
        //在遮罩画完之后，画上字和加载点
        if (Checker.isNull(bean.getBitmapCover())) {
            if (state == STATE_HAS_DATA) {//有数据时显示加载中的动画
                for (int i = 0; i < 3; i++) {
                    paint.setColor(i == dotCount % 3 ? colorDotDark : colorDotLight);
                    canvas.drawRoundRect(bean.getX() + UI.getPx(R.dimen.wpx387) + i * (dotHeight + dotDistance), viewHeight - UI.getPx(R.dimen.wpx735) - dotHeight, bean.getX() + UI.getPx(R.dimen.wpx387) + i * (dotHeight + dotDistance) + dotHeight, viewHeight - UI.getPx(R.dimen.wpx735), dotHeight / 2f, dotHeight / 2f, paint);
                }
                textPaint.setTextSize(textSize30);
                textPaint.setColor(colorDotDark);
                String str = "封面加载中";
                textPaint.getTextBounds(str, 0, str.length(), rect);
                canvas.drawText(str, bean.getX() + UI.getPx(R.dimen.wpx386), viewHeight - UI.getPx(R.dimen.wpx652), textPaint);
            }
        }
        //画老师头像、今日阅读、题目、老师名字
        textPaint.setTextSize(textSize36);
        textPaint.setColor(colorText);
        String str = "今日阅读";
        textPaint.getTextBounds(str, 0, str.length(), rect);
        canvas.drawText(str, UI.getPx(R.dimen.wpx276) + bean.getX(), viewHeight - UI.getPx(R.dimen.wpx225), textPaint);
        //画标题
        textPaint.setTextSize(textSize44);
        textPaint.setFakeBoldText(true);
        String strTitle = bean.getTitle();
        String tempTitle = bean.getTitle();
        textPaint.getTextBounds(strTitle, 0, strTitle.length(), rect);
        //调整最大的文字显示宽度
        float maxTextWidth = maxTitleOrTeacherNameWidth2;
        if (bean.getPosition() == 0 || !bean.isUnlock()) maxTextWidth = maxTitleOrTeacherNameWidth;
        if (rect.width() > maxTextWidth) {
            while (rect.width() > maxTextWidth) {
                strTitle = strTitle.substring(0, strTitle.length() - 1);
                tempTitle = strTitle + "...";
                textPaint.getTextBounds(tempTitle, 0, tempTitle.length(), rect);
            }
            strTitle = tempTitle;
        }
        canvas.drawText(strTitle, UI.getPx(R.dimen.wpx276) + bean.getX(), viewHeight - UI.getPx(R.dimen.wpx174), textPaint);
        textPaint.setFakeBoldText(false);
        //画老师名字和头像
        textPaint.setTextSize(textSize40);
        String strName = bean.getTeacherName();
        String tempTeacherName = bean.getTeacherName();
        textPaint.getTextBounds(strName, 0, strName.length(), rect);
        if (rect.width() > maxTextWidth) {
            while (rect.width() > maxTextWidth) {
                strName = strName.substring(0, strName.length() - 1);
                tempTeacherName = strName + "...";
                textPaint.getTextBounds(tempTeacherName, 0, tempTeacherName.length(), rect);
            }
            strName = tempTeacherName;
        }
        textPaint.getTextBounds(strName, 0, strName.length(), rect);
        canvas.drawText(strName, UI.getPx(R.dimen.wpx276) + bean.getX(), viewHeight - UI.getPx(R.dimen.wpx122), textPaint);
        if (Checker.notNull(bean.getBitmapTeacher())) {//画老师头像
            rectF.set(bean.getX() + UI.getPx(R.dimen.wpx110), viewHeight - UI.getPx(R.dimen.wpx120) - teacherHeight, bean.getX() + UI.getPx(R.dimen.wpx110) + teacherWidth, viewHeight - UI.getPx(R.dimen.wpx120));
            canvas.drawBitmap(bean.getBitmapTeacher(), null, rectF, paint);
        }
        //画今日打卡及进度条
        if (bean.getPosition() == 0) {
            textPaint.setTextSize(textSize28);
            textPaint.setColor(colorPunchText);
            String strTodayRead = statePunch == PUNCH_COMPLETED ? "今日打卡" : statePunch == PUNCH_WAIT_TO_SHARE ? "等待" : "今日";
            textPaint.getTextBounds(strTodayRead, 0, strTodayRead.length(), rect);
            canvas.drawText(strTodayRead, UI.getPx(R.dimen.wpx784) + bean.getX() - rect.width() / 2f, viewHeight - UI.getPx(R.dimen.wpx196) + rect.height() / 2f, textPaint);
            String strPunch = statePunch == PUNCH_COMPLETED ? "已完成" : statePunch == PUNCH_WAIT_TO_SHARE ? "家长分享" : "打卡";
            textPaint.getTextBounds(strPunch, 0, strPunch.length(), rect);
            canvas.drawText(strPunch, UI.getPx(R.dimen.wpx784) + bean.getX() - rect.width() / 2f, viewHeight - UI.getPx(R.dimen.wpx162) + rect.height() / 2f, textPaint);
            //画进度条
            paintProgress.setColor(colorProgressBg);
            rectF.set(bean.getX() + UI.getPx(R.dimen.wpx722), viewHeight - UI.getPx(R.dimen.wpx117) - progressCircleRadius * 2, bean.getX() + UI.getPx(R.dimen.wpx722) + progressCircleRadius * 2, viewHeight - UI.getPx(R.dimen.wpx117));
            canvas.drawArc(rectF, -90, 360, false, paintProgress);
            paintProgress.setColor(colorProgressFt);
            canvas.drawArc(rectF, -90, progress / 100f * 360f, false, paintProgress);
        } else if (!bean.isUnlock()) {
            rectF.set(bean.getX() + lockPaddingStart, viewHeight - lockPaddingBottom - lockHeight, bean.getX() + lockPaddingStart + lockWidth, viewHeight - lockPaddingBottom);
            if (Checker.isNull(bitmapLock) || bitmapLock.isRecycled()) {
                bitmapLock = BitmapFactory.decodeResource(getResources(), R.mipmap.home_ic_lock);
                bitmapLock = handleBitmap(bitmapLock, lockWidth, lockHeight);
            }
            canvas.drawBitmap(bitmapLock, null, rectF, paint);
        }
    }

    /**
     * 获取处理后的固定最大长度的字符串
     *
     * @param str 原字符串
     * @return 所求
     */
    private String getFormatStr(String str) {
        if (Checker.hasWord(str) && str.length() > TEXT_MAX_LENGTH) {
            str = str.substring(0, TEXT_MAX_LENGTH) + "...";
        }
        return str;
    }

    /**
     * 画指示点
     *
     * @param canvas 画布
     */
    private void drawIndicator(Canvas canvas) {
        if (Checker.hasNoList(list)) return;
        float width = indicatorWidth + 2 * indicatorHeight * list.size() - 1 + indicatorHeight;
        float temp = viewWidth / 2f - width / 2f;
        paint.setColor(colorIndicator);
        for (int i = 0; i < list.size(); i++) {
            temp += indicatorHeight / 2f;
            if (i == currentIndex) {
                canvas.drawRoundRect(temp, viewHeight - indicatorHeight, temp + indicatorWidth, viewHeight, indicatorHeight / 2f, indicatorHeight / 2f, paint);
                temp += indicatorWidth;
            } else {
                canvas.drawRoundRect(temp, viewHeight - indicatorHeight, temp + indicatorHeight, viewHeight, indicatorHeight / 2f, indicatorHeight / 2f, paint);
                temp += indicatorHeight;
            }
            temp += indicatorHeight / 2f;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (Checker.hasNoList(list)) return;
        for (int i = 0; i < list.size(); i++) {
            BannerBean bean = list.get(i);
            if (Checker.notNull(bean)) {
                canvas.save();
                canvas.scale(bean.getRatio(), bean.getRatio(), bean.getX(), viewHeight - paddingBottom);
                drawItem(canvas, bean);
                canvas.restore();
            }
        }
        drawIndicator(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));
    }

    /**
     * 获取宽或者高
     *
     * @param measureSpec 测量单位
     * @param isWidSpec   是宽还是高
     * @return 所求
     */
    private int measure(int measureSpec, boolean isWidSpec) {
        int result;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            viewWidth = ScreenUtils.getCurrentScreenWidth(getContext());//为了避免最后一个数字显示不全，加上一个右侧的内边距
            viewHeight = (int) (viewWidth * 1220 / 1200f);
            result = isWidSpec ? viewWidth : viewHeight;
            if (mode == MeasureSpec.AT_MOST) result = Math.min(result, size);
        }
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (valueAnimator != null && valueAnimator.isRunning()) return super.onTouchEvent(event);
        float x = event.getX();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://按下手指记录x坐标
                lastX = x;
                return true;
            case MotionEvent.ACTION_MOVE://滑动时计算滑动偏移值并且设置所有的条目的x坐标，实时更新
                scrollXOffset = x - lastX;
                scrollXOffset *= bigWidth / (viewWidth > 0 ? viewWidth : 1200);//避免滑过两个item导致错位。而且加上这个还带点视差效果
                setAllXOffset();
                invalidate();
                return true;
            case MotionEvent.ACTION_UP://手指抬起时，根据x坐标，自动判断目标条目，并进行动画滑动到目标条目
                autoSwitchItem(x, event.getY());
                performClick();
                return true;
            default:
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        UI.releaseTimer(timer);
        if (Checker.notNull(bitmapBgWhite) && !bitmapBgWhite.isRecycled()) {
            bitmapBgWhite.recycle();
            bitmapBgWhite = null;
        }
        if (Checker.notNull(bitmapMask) && !bitmapMask.isRecycled()) {
            bitmapMask.recycle();
            bitmapMask = null;
        }
        if (Checker.notNull(bitmapLock) && !bitmapLock.isRecycled()) {
            bitmapLock.recycle();
            bitmapLock = null;
        }
        if (Checker.notNull(bitmapCoverDefault) && !bitmapCoverDefault.isRecycled()) {
            bitmapCoverDefault.recycle();
            bitmapCoverDefault = null;
        }
        if (Checker.notNull(bitmapTeacherDefault) && !bitmapTeacherDefault.isRecycled()) {
            bitmapTeacherDefault.recycle();
            bitmapTeacherDefault = null;
        }
        if (Checker.hasList(list)) {
            for (int i = 0; i < list.size(); i++) {
                BannerBean bean = list.get(i);
                Bitmap bitmapCover = bean.getBitmapCover();
                if (bitmapCover != null && !bitmapCover.isRecycled()) {
                    bitmapCover.recycle();
                    bitmapCover = null;
                    list.get(i).setBitmapCover(null);
                }
                Bitmap bitmapTeacher = bean.getBitmapTeacher();
                if (bitmapTeacher != null && !bitmapTeacher.isRecycled()) {
                    bitmapTeacher.recycle();
                    bitmapTeacher = null;
                    list.get(i).setBitmapTeacher(null);
                }
            }
            list.clear();
            list = null;
        }
    }

    /**
     * 进行单位转换，从dp转成px
     *
     * @param dpValue dp大小
     * @return 所求
     */
    private int dp2px(float dpValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics());
    }

    /**
     * 回调接口
     */
    public interface callback {
        /**
         * 点击已解锁的学习计划
         *
         * @param planEn 学习计划
         */
        void onClickWithUnlock(NewPlanEn planEn);

        /**
         * 点击未解锁学习计划
         *
         * @param title 最新解锁的学习计划的标题
         */
        void onClickWithLock(String title);

        /**
         * 点击今日不可读的计划
         */
        void onClickTodayCanNotRead();

        /**
         * 点击了加载中的学习计划
         */
        void onClickLoading(String msg);
    }

    /**
     * 学习计划转变过来的滑动控件要用到的数据对象
     */
    public static class BannerBean implements Parcelable {
        public static final Creator<BannerBean> CREATOR = new Creator<BannerBean>() {
            @Override
            public BannerBean createFromParcel(Parcel source) {
                return new BannerBean(source);
            }

            @Override
            public BannerBean[] newArray(int size) {
                return new BannerBean[size];
            }
        };
        private String title;
        private String teacherName;
        private String cover;
        private String teacherHead;
        private int position;
        private float x;
        private float width;
        private float ratio;
        private float oldX;
        private float oldWidth;
        private float oldRatio;
        private Bitmap bitmapCover;
        private Bitmap bitmapTeacher;
        private boolean unlock;//是否已经解锁
        private boolean todayCanRead;//是否今日可读
        private NewPlanEn planEn;

        public BannerBean(String title, String teacherName, String cover, String teacherHead, int position, boolean unlock, boolean todayCanRead, NewPlanEn planEn) {
            this.title = title;
            this.teacherName = teacherName;
            this.cover = cover;
            this.teacherHead = teacherHead;
            this.position = position;
            this.unlock = unlock;
            this.todayCanRead = todayCanRead;
            this.planEn = planEn;
        }

        protected BannerBean(Parcel in) {
            this.title = in.readString();
            this.teacherName = in.readString();
            this.cover = in.readString();
            this.teacherHead = in.readString();
            this.position = in.readInt();
            this.x = in.readFloat();
            this.width = in.readFloat();
            this.ratio = in.readFloat();
            this.oldX = in.readFloat();
            this.oldWidth = in.readFloat();
            this.oldRatio = in.readFloat();
            this.bitmapCover = in.readParcelable(Bitmap.class.getClassLoader());
            this.bitmapTeacher = in.readParcelable(Bitmap.class.getClassLoader());
            this.unlock = in.readByte() != 0;
            this.todayCanRead = in.readByte() != 0;
            this.planEn = in.readParcelable(NewPlanEn.class.getClassLoader());
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getTeacherName() {
            return teacherName;
        }

        public void setTeacherName(String teacherName) {
            this.teacherName = teacherName;
        }

        public String getCover() {
            return cover;
        }

        public void setCover(String cover) {
            this.cover = cover;
        }

        public String getTeacherHead() {
            return teacherHead;
        }

        public void setTeacherHead(String teacherHead) {
            this.teacherHead = teacherHead;
        }

        public int getPosition() {
            return position;
        }

        public void setPosition(int position) {
            this.position = position;
        }

        public float getX() {
            return x;
        }

        public void setX(float x) {
            this.x = x;
        }

        public float getWidth() {
            return width;
        }

        public void setWidth(float width) {
            this.width = width;
        }

        public float getRatio() {
            return ratio;
        }

        public void setRatio(float ratio) {
            this.ratio = ratio;
        }

        public Bitmap getBitmapCover() {
            return bitmapCover;
        }

        public void setBitmapCover(Bitmap bitmapCover) {
            this.bitmapCover = bitmapCover;
        }

        public Bitmap getBitmapTeacher() {
            return bitmapTeacher;
        }

        public void setBitmapTeacher(Bitmap bitmapTeacher) {
            this.bitmapTeacher = bitmapTeacher;
        }

        public boolean isUnlock() {
            return unlock;
        }

        public void setUnlock(boolean unlock) {
            this.unlock = unlock;
        }

        public boolean isTodayCanRead() {
            return todayCanRead;
        }

        public void setTodayCanRead(boolean todayCanRead) {
            this.todayCanRead = todayCanRead;
        }

        public NewPlanEn getPlanEn() {
            return planEn;
        }

        public void setPlanEn(NewPlanEn planEn) {
            this.planEn = planEn;
        }

        public float getOldX() {
            return oldX;
        }

        public void setOldX(float oldX) {
            this.oldX = oldX;
        }

        public float getOldWidth() {
            return oldWidth;
        }

        public void setOldWidth(float oldWidth) {
            this.oldWidth = oldWidth;
        }

        public float getOldRatio() {
            return oldRatio;
        }

        public void setOldRatio(float oldRatio) {
            this.oldRatio = oldRatio;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(this.title);
            dest.writeString(this.teacherName);
            dest.writeString(this.cover);
            dest.writeString(this.teacherHead);
            dest.writeInt(this.position);
            dest.writeFloat(this.x);
            dest.writeFloat(this.width);
            dest.writeFloat(this.ratio);
            dest.writeFloat(this.oldX);
            dest.writeFloat(this.oldWidth);
            dest.writeFloat(this.oldRatio);
            dest.writeParcelable(this.bitmapCover, flags);
            dest.writeParcelable(this.bitmapTeacher, flags);
            dest.writeByte(this.unlock ? (byte) 1 : (byte) 0);
            dest.writeByte(this.todayCanRead ? (byte) 1 : (byte) 0);
            dest.writeParcelable(this.planEn, flags);
        }
    }
}